package net.wanho.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import net.wanho.constant.UserConstant;
import net.wanho.dto.*;
import net.wanho.exception.ServiceException;
import net.wanho.mapper.AuthInfoMapper;
import net.wanho.mapper.UserInfoMapper;
import net.wanho.mapper.UserRoleMapper;
import net.wanho.po.UserInfo;

import net.wanho.po.UserRole;
import net.wanho.service.FileService;
import net.wanho.service.UserInfoService;

import net.wanho.util.CurrentUtils;

import net.wanho.vo.PageInfo;
import net.wanho.vo.QueryAuthListVo;
import net.wanho.vo.QueryUserListVo;
import net.wanho.vo.queryRoleByIdVo;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author BGAll
 * @description 针对表【user_info(用户表)】的数据库操作Service实现
 * @createDate 2025-07-22 19:11:14
 */
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {
    private final AuthInfoMapper authInfoMapper;
    private final RedisTemplate<String, Object> redisTemplate;
    private final UserRoleMapper userRoleMapper;
    private final FileService fileService;

    @Override
    public List<QueryAuthListVo> queryAuthList() {
        // 先从redis中获取
        if (redisTemplate.hasKey(UserConstant.MENU_PREFIX + CurrentUtils.getId())) {
            return (List<QueryAuthListVo>) redisTemplate.opsForValue().get(UserConstant.MENU_PREFIX + CurrentUtils.getId());
        }

        // 先获取当前用户的所有角色
        Integer id = CurrentUtils.getId();
        List<Integer> roleIds = this.baseMapper.queryRoleIdsByUserId(id);
        if (ObjUtil.isEmpty(roleIds)) {
            throw new ServiceException("该用户无角色");
        }

        // 再根据roleIds获得权限id集合,记得去重
        List<Integer> authIds = this.baseMapper.queryAuthIdsByRoleIds(roleIds);

        // 先获取权限信息列表,再构建树形结构
        List<QueryAuthListVo> authList = authInfoMapper.queryAuthInfoList(authIds);

        List<QueryAuthListVo> treeAuthList = authList.stream().filter(auth -> auth.getParentId() == 0).sorted(Comparator.comparingInt(QueryAuthListVo::getAuthOrder)).map(item -> {
            findChildren(item, authList);
            return item;
        }).collect(Collectors.toList());
        redisTemplate.opsForValue().set(UserConstant.MENU_PREFIX + CurrentUtils.getId(), treeAuthList, UserConstant.MENU_EXPIRE_DATE, UserConstant.MENU_EXPIRE_UNIT);
        return treeAuthList;
    }

    @Override
    public PageInfo<QueryUserListVo> queryPage(QueryUserListDto queryUserListDto, int pageNum, int pageSize) {
        Page<UserInfo> userInfoPage = new Page<>(pageNum, pageSize);

        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.like(ObjUtil.isNotEmpty(queryUserListDto.getUserCode()), "ui.user_code", queryUserListDto.getUserCode())
                .eq(ObjUtil.isNotEmpty(queryUserListDto.getRoleId()), "ur.role_id", queryUserListDto.getRoleId())
                .eq(ObjUtil.isNotEmpty(queryUserListDto.getUserState()), "ui.user_state", queryUserListDto.getUserState())
                .eq("ui.is_delete", "0");

        this.baseMapper.selectByPage(userInfoPage, wrapper);
        PageInfo<QueryUserListVo> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(userInfoPage.getCurrent());
        pageInfo.setPageSize(userInfoPage.getSize());
        pageInfo.setTotalNum(userInfoPage.getTotal());

        ArrayList<QueryUserListVo> queryUserListVos = new ArrayList<>();
        userInfoPage.getRecords().forEach(item ->{
            QueryUserListVo queryUserListVo = new QueryUserListVo();
            BeanUtils.copyProperties(item, queryUserListVo);
            queryUserListVos.add(queryUserListVo);
        });

        pageInfo.setResultList(queryUserListVos);
        pageInfo.setPageCount(userInfoPage.getPages());
        pageInfo.setLimitIndex(userInfoPage.offset());

        return pageInfo;
    }

    @Override
    @Transactional
    public void saveUser(AddUserDto addUserDto) {
        UserInfo userExist = this.baseMapper.selectOne(new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getUserCode, addUserDto.getUserCode())
                .eq(UserInfo::getIsDelete, "0"));
        if (ObjUtil.isNotEmpty(userExist)) {
            throw new ServiceException("用户已存在");
        }
        // 先添加用户信息表
        UserInfo userInfo = new UserInfo();
        userInfo.setUserCode(addUserDto.getUserCode());
        userInfo.setUserName(addUserDto.getUserName());
        userInfo.setUserPwd(SecureUtil.md5(addUserDto.getUserPwd()));
        this.baseMapper.insert(userInfo);

        // 再添加用户角色表
        UserRole userRole = new UserRole();
        userRole.setUserId(userInfo.getUserId());
        userRole.setRoleId(3);
        userRoleMapper.insert(userRole);

    }

    @Override
    @Transactional
    public void modifyById(modifyUserDto modifyUserDto) {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(modifyUserDto.getUserId());
        userInfo.setUserName(modifyUserDto.getUserName());
        userInfo.setUserCode(modifyUserDto.getUserCode());
        this.baseMapper.updateById(userInfo);
    }

    @Override
    @Transactional
    public void removeUserById(Integer id) {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(id);
        userInfo.setIsDelete("1");
        this.baseMapper.updateById(userInfo);
    }

    @Override
    @Transactional
    public void removeUserByIds(Integer[] ids) {
        this.baseMapper.updateByIds(ids);
    }

    @Override
    @Transactional
    public void updatePwd(Integer id) {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(id);
        userInfo.setUserPwd(SecureUtil.md5("123456"));
        this.baseMapper.updateById(userInfo);
    }

    @Override
    public List<queryRoleByIdVo> queryRoleById(Integer id) {
        return this.baseMapper.selectRoleById(id);
    }

    @Override
    public List<Integer> queryAuthIds(Integer userId) {
        return this.baseMapper.queryAuthIds(userId);
    }

    @SneakyThrows
    @Override
    @Transactional
    public List<QueryUserListVo> exportTable(QueryUserListDto queryUserListDto, Integer pageNum, Integer pageSize, HttpServletResponse response) {
        Page<UserInfo> userInfoPage = new Page<>(pageNum, pageSize);

        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.like(ObjUtil.isNotEmpty(queryUserListDto.getUserCode()), "ui.user_code", queryUserListDto.getUserCode())
                .eq(ObjUtil.isNotEmpty(queryUserListDto.getRoleId()), "ur.role_id", queryUserListDto.getRoleId())
                .eq(ObjUtil.isNotEmpty(queryUserListDto.getUserState()), "ui.user_state", queryUserListDto.getUserState())
                .eq("ui.is_delete", "0");

        this.baseMapper.selectByPage(userInfoPage, wrapper);

        ArrayList<QueryUserListVo> queryUserListVos = new ArrayList<>();
        userInfoPage.getRecords().forEach(item ->{
            QueryUserListVo queryUserListVo = new QueryUserListVo();
            BeanUtils.copyProperties(item, queryUserListVo);
            queryUserListVos.add(queryUserListVo);
        });

        return queryUserListVos;
    }

    @Override
    @Transactional
    public void modifyPwd(ModifyPwdDto modifyPwdDto) {
        String userPwd = this.baseMapper.selectById(modifyPwdDto.getId()).getUserPwd();
        if (!ObjUtil.equals(userPwd,SecureUtil.md5(modifyPwdDto.getOldPassword()))) {
            throw new ServiceException("旧密码错误");
        }
        this.baseMapper.modifyPwd(modifyPwdDto);
    }

    @Override
    @Transactional
    public void modifySelf(ModifySelfDto modifySelfDto) {
        UserInfo userInfo = this.baseMapper.selectById(modifySelfDto.getUserId());
        if (ObjUtil.equals(userInfo.getUserCode(),modifySelfDto.getUserCode())) {
            if (!ObjUtil.equals(userInfo.getUserId(),modifySelfDto.getUserId()))
                throw new ServiceException("用户名不能重复!");
        }
        this.baseMapper.modifySelf(modifySelfDto);
    }

    @Override
    public String modifyAvatar(Integer id, MultipartFile file) {
        String url = fileService.uploadFile(file);

        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(id);
        userInfo.setAvatar(url);
        this.updateById(userInfo);

        return url;
    }

    private void findChildren(QueryAuthListVo item, List<QueryAuthListVo> authList) {
        List<QueryAuthListVo> children = authList.stream().filter(auth -> auth.getParentId() == (item.getAuthId())).map(subItem -> {
            findChildren(subItem, authList);
            return subItem;
        }).collect(Collectors.toList());
        item.setChildAuth(children);
    }


}